#include "TcpClientImpl.h"
#include <iostream>
// #include "event2/util.h"

void ReconnectCB(int fd, short event, void *arg) 
{
    std::cout << "ReconnectCB" << std::endl;
    // event_add(&ev, &tv); // 重新注册

    CTcpClientImpl *pTcpImpl = reinterpret_cast<CTcpClientImpl*>(arg);
    if (pTcpImpl == nullptr) {
        std::cout << "ReconnectCB pTcpImpl == nullptr" << std::endl;
        return;
    }

    if (!pTcpImpl->Connect(pTcpImpl->_dstIp, pTcpImpl->_dstPort, pTcpImpl->_reconnectTimeval)) {
        timeval tv;
        tv.tv_sec = pTcpImpl->_reconnectTimeval;
        event_add(&pTcpImpl->_reconnectEvent, &tv);
    } else {
        event_del(&pTcpImpl->_reconnectEvent);
    }
}

void ReadMsg(bufferevent *bev, void *arg)
{
    CTcpClientImpl *pTcpImpl = reinterpret_cast<CTcpClientImpl*>(arg);
    if (pTcpImpl == nullptr) { return; }
    pTcpImpl->OnReadMsg(bev);
}

void Status(bufferevent *bev, short event, void *arg)
{
    if (arg == nullptr) { return; }
    CTcpClientImpl *pTcpImpl = reinterpret_cast<CTcpClientImpl*>(arg);
    pTcpImpl->OnStatus(bev, event);
}

void CmdMsgCb(int fd, short evnts, void *arg)
{
    char msg[1024];
    int ret = read(fd, msg, sizeof(msg));
    if (ret < 0) {
        std::cerr << "read fail." << std::endl;
        exit(1);
    }

    CTcpClientImpl *pTcpImpl = (CTcpClientImpl*)arg;

    // 把终端的消息发送给服务器端
    bufferevent_write(pTcpImpl->_pBev, msg, ret);
}

CTcpClientImpl::CTcpClientImpl(ReadMsgCB readMsgCB, StatusCB statusCB)
    : CTcpClient(readMsgCB, statusCB), _readMsgCB(readMsgCB), _statusCB(statusCB)
{
    _pBase = event_base_new();
    _pBev = bufferevent_socket_new(_pBase, -1, BEV_OPT_CLOSE_ON_FREE);

    _pCmdEvent = event_new(_pBase, STDIN_FILENO, EV_READ | EV_PERSIST, CmdMsgCb, (void*)this);
    event_add(_pCmdEvent, nullptr);

    // timeval writeTimeval;
    // writeTimeval.tv_sec = 1;
    // bufferevent_set_timeouts(_pBev, &writeTimeval, &writeTimeval);
    bufferevent_setcb(_pBev, ReadMsg, nullptr, Status, (void*)this);
    bufferevent_enable(_pBev, EV_READ | EV_PERSIST);
}

CTcpClientImpl::~CTcpClientImpl()
{

}

bool CTcpClientImpl::Connect(const std::string &dstIp, const uint16_t &port, const int &reTimeval)
{
    _reconnectTimeval = reTimeval;
    if (reTimeval > 0) {
        event_set(&_reconnectEvent, -1, 0, ReconnectCB, this);
        // timeval tv;
        // tv.tv_usec = reTimeval * 1000;
        event_base_set(_pBase, &_reconnectEvent);
    }
    _dstIp = dstIp;
    _dstPort = port;

    std::string url = dstIp + ":" + std::to_string(port);
    std::cout << "url: " << url << std::endl;
    sockaddr server_addr;
    int serverAddrLen = sizeof(server_addr);
    if (-1 == evutil_parse_sockaddr_port(url.c_str(), &server_addr, &serverAddrLen)) {
        std::cout << "evutil_parse_sockaddr_port failed, url: " << url << std::endl;
        return false;
    }

    // _dstIp = dstIp;
    // _dstPort = port;
    // sockaddr_in server_addr;
    // server_addr.sin_family = AF_INET;
    // server_addr.sin_port = htons(_dstPort);
    // inet_aton(_dstIp.c_str(), &server_addr.sin_addr);

    int rst = bufferevent_socket_connect(_pBev, (sockaddr*)&server_addr, sizeof(server_addr));
    if (rst != 0) {
        // return false;
        std::cout << "bufferevent_socket_connect failed." << std::endl;
        return false;
    }

    // timeval tv;
    // tv.tv_sec = _reconnectTimeval;
    // event_add(&_reconnectEvent, &tv);
    
    return true;
}

bool CTcpClientImpl::Run()
{
    if (event_base_dispatch(_pBase) == 0) {
        bufferevent_free(_pBev);
        event_base_free(_pBase);
    }
    return true;
}

bool CTcpClientImpl::SetReadMsgCB(ReadMsgCB msgCB)
{
    _readMsgCB = msgCB;
    return true;
}
bool CTcpClientImpl::SetStatusCB(StatusCB statusCB)
{
    _statusCB = statusCB;
    return true;
}

bool CTcpClientImpl::SendMsg(const std::string &msg)
{
    return bufferevent_write(_pBev, msg.c_str(), msg.size()) == 0;
}

void CTcpClientImpl::OnReadMsg(bufferevent* bev)
{
    uint32_t bufLen = evbuffer_get_length(bev->input);
    std::cout << "OnReadMsg bufLen: " << bufLen << std::endl;


    char msg[1024];
    size_t len = bufferevent_read(bev, msg, sizeof(msg));
    msg[len] = '\0';

    if (_readMsgCB != nullptr) {
        _readMsgCB(msg, len);
    }
}

void CTcpClientImpl::OnStatus(bufferevent *bev, short event)
{
    ClientStatus status;
    int err = EVUTIL_SOCKET_ERROR();
    if (event & BEV_EVENT_EOF) {
        // std::cerr << "tcp eof." << std::endl;
        // status = ClientStatus::ReadEof;
        status = ClientStatus::Closed;
    } else if (event & BEV_EVENT_ERROR) {
        std::cerr << "some other error: " << err << std::endl;
        // 这将自动close套接字和free读写缓冲区
        // bufferevent_free(bev);
        status = ClientStatus::Error;
        // event_base_loopbreak(_pBase);

        timeval tv;
        tv.tv_sec = _reconnectTimeval;
        event_add(&_reconnectEvent, &tv);
    } else if (event & BEV_EVENT_CONNECTED) {
        // std::cout << "the client has connected to server." << std::endl;
        status = ClientStatus::Connected;
        event_del(&_reconnectEvent);
    } else if (event & BEV_EVENT_TIMEOUT) {
        // std::cout << "the client BEV_EVENT_TIMEOUT." << std::endl;
        status = ClientStatus::Timeout;
    }
    if (_statusCB != nullptr) {
        _statusCB(status);
    }
}